package com.sc.nft.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.*;
import com.sc.nft.dto.UserEcologyHatchRecordsDao;
import com.sc.nft.entity.EcologyPoolDaoRankConf;
import com.sc.nft.entity.EcologyPoolDaoRankIncomeConf;
import com.sc.nft.entity.UserCreatorInfo;
import com.sc.nft.entity.dto.EcologyPoolCreateDaoRankConfIncomeDTO;
import com.sc.nft.entity.vo.ExcellentBrandRankingVO;
import com.sc.nft.entity.vo.ecologypool.EcologyPoolDaoRankConfDetailIncomeVO;
import com.sc.nft.entity.vo.ecologypool.EcologyPoolDaoRankConfDetailVO;
import com.sc.nft.entity.vo.ecologypool.EcologyPoolDaoRankConfVO;
import com.sc.nft.enums.EcologyPoolDaoRankTypeEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.EcologyPoolDaoRankConfService;
import com.sc.nft.util.LocalDateTimeUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author PC
 * @description 针对表【sc_ecology_pool_dao_rank_conf(生态池-品牌榜配置)】的数据库操作Service实现
 * @createDate 2024-07-16 19:05:30
 */
@Slf4j
@Service
@AllArgsConstructor
public class EcologyPoolDaoRankConfServiceImpl implements EcologyPoolDaoRankConfService {
    private final EcologyPoolDaoRankConfDao ecologyPoolDaoRankConfDao;
    private final UserCreatorInfoDao userCreatorInfoDao;
    private final UserCollectionDao userCollectionDao;
    private final UserEcologyHatchRecordsDao userEcologyHatchRecordsDao;
    private final PayOrderDao payOrderDao;
    private final SandTransferRecordDao sandTransferRecordDao;
    private final EcologyPoolDaoRankIncomeConfDao ecologyPoolDaoRankIncomeConfDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createDaoRankConf(String rankName, EcologyPoolDaoRankTypeEnum rankType, BigDecimal userRatio, BigDecimal ecologyRatio, BigDecimal cashInRatio, BigDecimal contributionThreshold, Date startTime, Date endTime, String activityRule, String topImage, List<EcologyPoolCreateDaoRankConfIncomeDTO> ecologyPoolCreateDaoRankConfIncomeDTOS) {
        //校验参数
        checkCreateDaoRankConfRequest(userRatio, ecologyRatio, cashInRatio);
        //校验时间
        checkTime(rankType, startTime, endTime);
        EcologyPoolDaoRankConf ecologyPoolDaoRankConf = new EcologyPoolDaoRankConf();
        ecologyPoolDaoRankConf.setRankName(rankName);
        ecologyPoolDaoRankConf.setRankType(rankType);
        ecologyPoolDaoRankConf.setUserRatio(userRatio);
        ecologyPoolDaoRankConf.setEcologyRatio(ecologyRatio);
        ecologyPoolDaoRankConf.setCashInRatio(cashInRatio);
        ecologyPoolDaoRankConf.setContributionThreshold(contributionThreshold);
        ecologyPoolDaoRankConf.setStartTime(startTime);
        ecologyPoolDaoRankConf.setEndTime(endTime);
        ecologyPoolDaoRankConf.setActivityRule(activityRule);
        ecologyPoolDaoRankConf.setTopImage(topImage);
        if (!ecologyPoolDaoRankConfDao.save(ecologyPoolDaoRankConf)) {
            throw new GlobalRunTimeException("品牌榜配置新增失败!");
        }
        List<EcologyPoolDaoRankIncomeConf> incomeConfList = new ArrayList<>();
        for (EcologyPoolCreateDaoRankConfIncomeDTO ecologyPoolCreateDaoRankConfIncomeDTO : ecologyPoolCreateDaoRankConfIncomeDTOS) {
            EcologyPoolDaoRankIncomeConf incomeConf = getEcologyPoolDaoRankIncomeConf(ecologyPoolCreateDaoRankConfIncomeDTO, ecologyPoolDaoRankConf);
            incomeConfList.add(incomeConf);
        }
        if (!ecologyPoolDaoRankIncomeConfDao.saveBatch(incomeConfList)) {
            throw new GlobalRunTimeException("品牌榜收益配置新增失败!");
        }
    }

    @Override
    public void deleteDaoRankConf(Long id) {
        EcologyPoolDaoRankConf ecologyPoolDaoRankConf = ecologyPoolDaoRankConfDao.getById(id);
        if (ObjectUtil.isNull(ecologyPoolDaoRankConf)) {
            throw new GlobalRunTimeException("品牌榜不存在");
        }
        if (LocalDateTime.now().isAfter(LocalDateTimeUtil.dateToLocalDateTime(ecologyPoolDaoRankConf.getStartTime()))) {
            throw new GlobalRunTimeException("当前时间大于开启时间,不允许删除");
        }
        boolean flag = ecologyPoolDaoRankConf.deleteById();
        if (!flag) {
            throw new GlobalRunTimeException("删除失败");
        }
    }

    private void checkCreateDaoRankConfRequest(BigDecimal userRatio, BigDecimal ecologyRatio, BigDecimal cashInRatio) {
        Assert.isTrue(userRatio.compareTo(BigDecimal.ZERO) > 0, () -> new GlobalRunTimeException("用户系数必须大于0"));
        Assert.isTrue(ecologyRatio.compareTo(BigDecimal.ZERO) > 0, () -> new GlobalRunTimeException("熔炼系数必须大于0"));
        Assert.isTrue(cashInRatio.compareTo(BigDecimal.ZERO) > 0, () -> new GlobalRunTimeException("入金系数必须大于0"));
    }

    private void checkTime(EcologyPoolDaoRankTypeEnum rankType, Date startTime, Date endTime) {
        LocalDateTime startLocalTime = LocalDateTimeUtil.dateToLocalDateTime(startTime);
        LocalDateTime endLocalTime = LocalDateTimeUtil.dateToLocalDateTime(endTime);
        Date rankConfLastTime = getRankConfLastTime(rankType);
        if (ObjectUtil.isNull(rankConfLastTime) && startLocalTime.isBefore(LocalDateTime.now())) {
            throw new GlobalRunTimeException("开始时间必须在当前时间之后");
        }
        if (ObjectUtil.isNotNull(rankConfLastTime)) {
            LocalDateTime lastTimeLocalTime = LocalDateTimeUtil.dateToLocalDateTime(rankConfLastTime);
            if (lastTimeLocalTime.isBefore(LocalDateTime.now()) && startLocalTime.isBefore(LocalDateTime.now())) {
                throw new GlobalRunTimeException("开始时间必须在当前时间之后");
            }
            if (startLocalTime.isBefore(lastTimeLocalTime)) {
                throw new GlobalRunTimeException("开始时间必须在上一次结束时间之后");
            }
        }
        Duration duration = Duration.between(startLocalTime, endLocalTime);
        if (duration.toHours() < 24) {
            throw new GlobalRunTimeException("结束时间必须大于开启时间24小时");
        }
    }

    @Override
    public Date getRankConfLastTime(EcologyPoolDaoRankTypeEnum ecologyPoolDaoRankTypeEnum) {
        EcologyPoolDaoRankConf ecologyPoolDaoRankConf = ecologyPoolDaoRankConfDao.getRankConfLastTime(ecologyPoolDaoRankTypeEnum);
        if (ObjectUtil.isNull(ecologyPoolDaoRankConf)) {
            return null;
        }
        return ecologyPoolDaoRankConf.getEndTime();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDaoRankConf(Long id, String activityRule, String topImage) {
        EcologyPoolDaoRankConf ecologyPoolDaoRankConf = ecologyPoolDaoRankConfDao.getById(id);
        Assert.notNull(ecologyPoolDaoRankConf, () -> new GlobalRunTimeException("榜单不存在"));
        Assert.isFalse(ecologyPoolDaoRankConf.getStatus(), () -> new GlobalRunTimeException("榜单已开启，不能修改"));
        ecologyPoolDaoRankConf = new EcologyPoolDaoRankConf();
        ecologyPoolDaoRankConf.setId(id);
        ecologyPoolDaoRankConf.setActivityRule(activityRule);
        ecologyPoolDaoRankConf.setTopImage(topImage);
        if (!ecologyPoolDaoRankConfDao.updateById(ecologyPoolDaoRankConf)) {
            throw new GlobalRunTimeException("品牌榜配置修改失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDaoRankConfStatus(Long id, Boolean status) {
        EcologyPoolDaoRankConf ecologyPoolDaoRankConf = new EcologyPoolDaoRankConf();
        ecologyPoolDaoRankConf.setId(id);
        ecologyPoolDaoRankConf.setStatus(status);
        if (!ecologyPoolDaoRankConfDao.updateById(ecologyPoolDaoRankConf)) {
            throw new GlobalRunTimeException("品牌榜上下架失败");
        }
    }

    @Override
    public EcologyPoolDaoRankConfDetailVO daoRankConfDetail(Long id) {
        EcologyPoolDaoRankConf ecologyPoolDaoRankConf = ecologyPoolDaoRankConfDao.getById(id);
        if (Objects.isNull(ecologyPoolDaoRankConf)) {
            throw new GlobalRunTimeException("榜单id不存在");
        }
        EcologyPoolDaoRankConfDetailVO ecologyPoolDaoRankConfDetailVO = new EcologyPoolDaoRankConfDetailVO();
        ecologyPoolDaoRankConfDetailVO.setId(ecologyPoolDaoRankConf.getId());
        ecologyPoolDaoRankConfDetailVO.setRankName(ecologyPoolDaoRankConf.getRankName());
        ecologyPoolDaoRankConfDetailVO.setRankType(ecologyPoolDaoRankConf.getRankType());
        ecologyPoolDaoRankConfDetailVO.setUserRatio(ecologyPoolDaoRankConf.getUserRatio());
        ecologyPoolDaoRankConfDetailVO.setEcologyRatio(ecologyPoolDaoRankConf.getEcologyRatio());
        ecologyPoolDaoRankConfDetailVO.setCashInRatio(ecologyPoolDaoRankConf.getCashInRatio());
        ecologyPoolDaoRankConfDetailVO.setContributionThreshold(ecologyPoolDaoRankConf.getContributionThreshold());
        ecologyPoolDaoRankConfDetailVO.setStartTime(ecologyPoolDaoRankConf.getStartTime());
        ecologyPoolDaoRankConfDetailVO.setEndTime(ecologyPoolDaoRankConf.getEndTime());
        ecologyPoolDaoRankConfDetailVO.setActivityRule(ecologyPoolDaoRankConf.getActivityRule());
        ecologyPoolDaoRankConfDetailVO.setTopImage(ecologyPoolDaoRankConf.getTopImage());

        List<EcologyPoolDaoRankIncomeConf> list = ecologyPoolDaoRankIncomeConfDao.getConfigId(id);
        List<EcologyPoolDaoRankConfDetailIncomeVO> detailIncomeVOS = new ArrayList<>();
        for (EcologyPoolDaoRankIncomeConf ecologyPoolDaoRankIncomeConf : list) {
            EcologyPoolDaoRankConfDetailIncomeVO ecologyPoolDaoRankConfDetailIncomeVO = getEcologyPoolDaoRankConfDetailIncomeVO(ecologyPoolDaoRankIncomeConf);
            detailIncomeVOS.add(ecologyPoolDaoRankConfDetailIncomeVO);
        }
        ecologyPoolDaoRankConfDetailVO.setIncomeList(detailIncomeVOS);
        return ecologyPoolDaoRankConfDetailVO;
    }

    @Override
    public IPage<EcologyPoolDaoRankConfVO> daoRankConfPage(int pageNo, int pageSize, String rankName) {
        Page<EcologyPoolDaoRankConf> ecologyPoolDaoRankConfPage = ecologyPoolDaoRankConfDao.daoRankPage(pageNo, pageSize, rankName);
        return ecologyPoolDaoRankConfPage.convert(x -> {
            EcologyPoolDaoRankConfVO vo = new EcologyPoolDaoRankConfVO();
            vo.setId(x.getId());
            vo.setRankName(x.getRankName());
            vo.setRankType(x.getRankType());
            vo.setJoinRankCount(x.getJoinRankCount());
            vo.setStatus(x.getStatus());
            vo.setStartTime(x.getStartTime());
            vo.setEndTime(x.getEndTime());
            return vo;
        });
    }

    private static EcologyPoolDaoRankConfDetailIncomeVO getEcologyPoolDaoRankConfDetailIncomeVO(EcologyPoolDaoRankIncomeConf ecologyPoolDaoRankIncomeConf) {
        EcologyPoolDaoRankConfDetailIncomeVO ecologyPoolDaoRankConfDetailIncomeVO = new EcologyPoolDaoRankConfDetailIncomeVO();
        ecologyPoolDaoRankConfDetailIncomeVO.setIncomeName(ecologyPoolDaoRankIncomeConf.getIncomeName());
        ecologyPoolDaoRankConfDetailIncomeVO.setSort(ecologyPoolDaoRankIncomeConf.getSort());
        ecologyPoolDaoRankConfDetailIncomeVO.setStartRank(ecologyPoolDaoRankIncomeConf.getStartRank());
        ecologyPoolDaoRankConfDetailIncomeVO.setEndRank(ecologyPoolDaoRankIncomeConf.getEndRank());
        ecologyPoolDaoRankConfDetailIncomeVO.setContributionThreshold(ecologyPoolDaoRankIncomeConf.getContributionThreshold());
        ecologyPoolDaoRankConfDetailIncomeVO.setPrizeRatio(ecologyPoolDaoRankIncomeConf.getPrizeRatio());
        return ecologyPoolDaoRankConfDetailIncomeVO;
    }

    private static EcologyPoolDaoRankIncomeConf getEcologyPoolDaoRankIncomeConf(EcologyPoolCreateDaoRankConfIncomeDTO ecologyPoolCreateDaoRankConfIncomeDTO, EcologyPoolDaoRankConf ecologyPoolDaoRankConf) {
        EcologyPoolDaoRankIncomeConf incomeConf = new EcologyPoolDaoRankIncomeConf();
        incomeConf.setEcologyPoolDaoRankConfId(ecologyPoolDaoRankConf.getId());
        incomeConf.setSort(ecologyPoolCreateDaoRankConfIncomeDTO.getSort());
        incomeConf.setPrizeRatio(ecologyPoolCreateDaoRankConfIncomeDTO.getPrizeRatio());
        incomeConf.setIncomeName(ecologyPoolCreateDaoRankConfIncomeDTO.getIncomeName());
        incomeConf.setStartRank(ecologyPoolCreateDaoRankConfIncomeDTO.getStartRank());
        incomeConf.setEndRank(ecologyPoolCreateDaoRankConfIncomeDTO.getEndRank());
        incomeConf.setContributionThreshold(ecologyPoolCreateDaoRankConfIncomeDTO.getContributionThreshold());
        return incomeConf;
    }

    @Override
    public List<EcologyPoolDaoRankConf> getActiveRankings() {
        List<EcologyPoolDaoRankConf> result = ecologyPoolDaoRankConfDao.getActiveRankings();
        return result;
    }

    @Override
    public List<ExcellentBrandRankingVO> excellentBrandRanking(EcologyPoolDaoRankConf activeRanking) {
        List<ExcellentBrandRankingVO> result = new ArrayList<>();
        // 获取当前需要排名的dao.
        List<UserCreatorInfo> enableJoinRankDao = userCreatorInfoDao.getEnableJoinRankDao();
        if (CollUtil.isEmpty(enableJoinRankDao)) {
            return null;
        }
        enableJoinRankDao.forEach(userCreatorInfo -> {
            // 获取这个dao的助理人下,活动时间内所有新增的用户,并且获取他们所有的消费or熔炼满1000的.
            Long userId = userCreatorInfo.getUserId();
            // 获取当前这个dao下排除新增的市值账号外的所有的满足持仓或熔炼条件的用户
            Integer nationalTreasuryIncreaseCount = userCollectionDao.getNationalTreasuryIncreaseCount(userId, activeRanking.getStartTime(), activeRanking.getEndTime());
            // 获取活动期间的熔炼值
            BigDecimal smeltingValue = userEcologyHatchRecordsDao.getSmeltingValue(userId, activeRanking.getStartTime(), activeRanking.getEndTime());
            // 系数1/系数后保留2位
            BigDecimal v1 = BigDecimal.ONE.divide(Convert.toBigDecimal(activeRanking.getUserRatio()), 2, BigDecimal.ROUND_HALF_UP);
            BigDecimal k2 = BigDecimal.ONE.divide(Convert.toBigDecimal(activeRanking.getEcologyRatio()), 2, BigDecimal.ROUND_HALF_UP);
            BigDecimal k3 = BigDecimal.ONE.divide(Convert.toBigDecimal(activeRanking.getCashInRatio()), 2, BigDecimal.ROUND_HALF_UP);
            // 获取品牌的入金
            BigDecimal enterMoney = payOrderDao.getNationalTreasuryEnterMoney(userId, activeRanking.getStartTime(), activeRanking.getEndTime());
            // 获取品牌的出金
            BigDecimal outMoney = sandTransferRecordDao.getNationalTreasuryOutMoney(userId, activeRanking.getStartTime(), activeRanking.getEndTime());
            // 贡献值计算公式:
            /*品牌贡献值=本次活动时间段内的新增品牌用户数（条件为：品牌持仓总额或熔炼总额大于等于1000）*用户系数K1
                    +本次活动时间段内的熔炼值*熔炼系数K2
                    +（本次活动时间段内的品牌入金-本次活动时间段内的品牌出金）/（本次活动时间段内的品牌入金+1）*入金系数K3（取整，K1,K2,K3后台可配置）。/*
             */
            // 贡献值 四舍五入保留整值
            BigDecimal contributionValue = Convert.toBigDecimal(nationalTreasuryIncreaseCount).multiply(v1)
                    .add(smeltingValue.multiply(k2))
                    .add(enterMoney.subtract(outMoney).multiply(k3));

            // 把所有的数据组装成对象
            ExcellentBrandRankingVO excellentBrandRankingVO = new ExcellentBrandRankingVO();
            excellentBrandRankingVO.setEnterMoney(enterMoney);
            excellentBrandRankingVO.setUserId(userId);
            excellentBrandRankingVO.setEcologyPoolDaoRankConfId(activeRanking.getId());
            excellentBrandRankingVO.setOutMoney(outMoney);
            excellentBrandRankingVO.setContributionValue(NumberUtil.isLess(contributionValue, BigDecimal.ZERO) ? BigDecimal.ZERO : contributionValue.setScale(0, BigDecimal.ROUND_HALF_UP));
            excellentBrandRankingVO.setSmeltingValue(smeltingValue);
            excellentBrandRankingVO.setDaoId(userCreatorInfo.getId());
            excellentBrandRankingVO.setRankName(userCreatorInfo.getDaoName());
            excellentBrandRankingVO.setNationalTreasuryIncreaseCount(nationalTreasuryIncreaseCount);
            result.add(excellentBrandRankingVO);
        });
        return result;
    }
}




